﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
using AMM.Business.Produce;
using AMM.Model;

namespace AMM.CommonControls {
    public partial class CustomDayCalendar : UserControl {

        public DateTime Date {
            get { return this._date; }
            set {
                this._date = value;
                this.pnlCalendarDay.Invalidate();
            }
        }

        private DateTime _date;
        private List<ProducePlan> _ppList;
        private List<DayData> _dayDataList;
        private DayData _currentDayData;

        public CustomDayCalendar() {
            InitializeComponent();
        }

        void pnlCalendarDay_MouseUp(object sender, MouseEventArgs e) {
            this.dgvList_Click(this.dgvList, EventArgs.Empty);
            if (this._dayDataList.Any(x => x.GraphicsPath.IsVisible(e.Location))) {
                this._currentDayData = this._dayDataList.First(x => x.GraphicsPath.IsVisible(e.Location));
                if (this._currentDayData.Date.HasValue) {
                    if (this._currentDayData.ProducePlans.Count == 0) { return; }
                    this.dgvList.Visible = true;

                    Point locationPoint = new Point(e.Location.X, e.Location.Y);
                    if (e.Location.X + this.dgvList.Width > this.Width) {
                        locationPoint.X = e.Location.X - this.dgvList.Width;
                    }
                    if (e.Location.Y + this.dgvList.Height > this.Height) {
                        locationPoint.Y = e.Location.Y - this.dgvList.Height;
                    }
                    this.dgvList.Location = locationPoint;

                    this.dgvList.Click += new EventHandler(dgvList_Click);
                    this.dgvList.DataSource = this._currentDayData.ProducePlans.Select(x => {
                        return new {
                            ProduceUnitCode = x.Basic.Code,
                            ProduceConductCode = x.ProduceConduct.Code,
                            PlanAmount = x.PlanAmount
                        };
                    }).ToList();
                }
            }
        }

        void dgvList_Click(object sender, EventArgs e) {
            this.dgvList.Visible = false;
            this.dgvList.Click -= new EventHandler(dgvList_Click);
        }

        void pnlCalendarDay_Paint(object sender, PaintEventArgs e) {
            this._dayDataList.Clear();
            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
            e.Graphics.CompositingQuality = CompositingQuality.HighQuality;

            DateTime dt = this.Date;
            DateTime dtFirstDate = new DateTime(dt.Year, dt.Month, 1);
            DayOfWeek dayOfWeek = dtFirstDate.DayOfWeek;
            DateTime dtCurrent = dtFirstDate;

            int days = DateTime.DaysInMonth(dtFirstDate.Year, dtFirstDate.Month);
            int titleHeight = 30;
            int weekDays = 7;
            int rows = (days + (int)dayOfWeek) % weekDays > 0
                ? (days + (int)dayOfWeek) / weekDays + 1
                : (days + (int)dayOfWeek) / weekDays;
            bool endFlag = false;

            Rectangle rec = new Rectangle();
            rec.Width = this.Width / weekDays;
            rec.Height = (this.Height - rows * 1 - titleHeight) / rows;

            Rectangle recTitle = new Rectangle();
            recTitle.Width = rec.Width;
            recTitle.Height = titleHeight;

            FontFamily ff = new FontFamily("Verdana");
            Font f = new Font(ff, 12, FontStyle.Regular);

            for (int w = 0; w < weekDays; w++) {
                recTitle.Location = new Point(recTitle.Width * w, 0);
                using (GraphicsPath gp = new GraphicsPath()) {
                    gp.AddRectangle(recTitle);
                    e.Graphics.FillPath(Brushes.LightGray, gp);
                }
                using (GraphicsPath gp = new GraphicsPath()) {
                    gp.AddRectangle(recTitle);
                    e.Graphics.DrawPath(Pens.Black, gp);
                }
                e.Graphics.DrawString(((DayOfWeek)w).ToString(), f, SystemBrushes.ControlText, recTitle,
                    new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });

            }

            for (int r = 0; r < rows; r++) {
                for (int w = 0; w < weekDays; w++) {
                    rec.Location = new Point(rec.Width * w, titleHeight + rec.Height * r);
                    DayData dayData = new DayData();
                    dayData.Date = null;
                    dayData.GraphicsPath = new GraphicsPath();
                    dayData.GraphicsPath.StartFigure();
                    dayData.GraphicsPath.AddRectangle(rec);

                    if (dtCurrent.DayOfWeek == (DayOfWeek)w && !endFlag) {
                        e.Graphics.DrawString(dtCurrent.ToShortDateString(), f, SystemBrushes.ControlText, rec);
                        if (this._ppList != null) {
                            dayData.Date = dtCurrent;
                            dayData.ProducePlans = this._ppList.Where(x => x.PlanDate == dtCurrent.Date).ToList();
                            string planString = string.Empty;
                            dayData.ProducePlans.Take(3).ToList().ForEach(x => {
                                planString += string.Format("{0}.{1}; ", x.Basic.Code, x.ProduceConduct.Code);
                            });
                            rec.Y += f.Height;
                            rec.X += 5;
                            planString = string.Format("{0}{1} ", planString, dayData.ProducePlans.Count > 3 ? "..." : string.Empty);
                            e.Graphics.DrawString(planString, new Font(f.FontFamily, 10, f.Style), new SolidBrush(Color.Red), rec);
                        }

                        dtCurrent = dtCurrent.AddDays(1);
                        endFlag = dtCurrent.Month != dtFirstDate.Month;
                    }

                    dayData.GraphicsPath.CloseFigure();
                    e.Graphics.DrawPath(SystemPens.ControlText, dayData.GraphicsPath);

                    this._dayDataList.Add(dayData);
                }
                if (endFlag) { break; }
            }
        }

        private void CustomDayCalendar_Resize(object sender, EventArgs e) {
            this.pnlCalendarDay.Invalidate();
        }

        private void CustomDayCalendar_Load(object sender, EventArgs e) {
            if (this.DesignMode) { return; }
            this._ppList = new ProducePlanProcessor().FetchProducePlanForView();
            this._dayDataList = new List<DayData>();

            this.pnlCalendarDay.Visible = true;
            this.dgvList.Visible = false;
            this.dgvList.AutoGenerateColumns = false;

            this.pnlCalendarDay.Paint += new PaintEventHandler(pnlCalendarDay_Paint);
            this.pnlCalendarDay.MouseUp += new MouseEventHandler(pnlCalendarDay_MouseUp);
        }
    }

    internal class DayData {
        public DateTime? Date { get; set; }
        public GraphicsPath GraphicsPath { get; set; }
        public List<ProducePlan> ProducePlans { get; set; }
    }
}
